<?php

namespace App\BO\User;

use App\BO\Coupon\CouponProductSkuCheck\CheckResultWrapper;
use App\BO\Coupon\CouponProductSkuCheck\CouponProductSkuCheckMeta;
use App\BO\Coupon\CouponProductSkuCheck\CouponProductSkuCheckProxy;
use App\Entities\AreaEntity;
use App\Entities\CartItemEntity;
use App\Entities\CouponCodeEntity;
use App\Entities\ProductEntity;
use App\Entities\ProductSkuEntity;
use App\Utils\Assert;
use App\Utils\PipelineProxy;

class UserCouponBO
{
    /**
     * @param CartItemEntity $cartItemEntity
     * @return array
     * @throws \Exception
     */
    private static function getConfigAndCheckMeta(CartItemEntity $cartItemEntity)
    {
        $productSkuEntity = ProductSkuEntity::find($cartItemEntity->getProductSkuId());
        Assert::notNull($productSkuEntity);

        $productEntity = ProductEntity::find($productSkuEntity->getProductId());
        Assert::notNull($productEntity);

        $areaEntity = AreaEntity::find($cartItemEntity->getCityId());
        Assert::notNull($areaEntity);

        $pipelineConfig = CouponProductSkuCheckProxy::getConfigEnv();
        $checkMeta = new CouponProductSkuCheckMeta();
        $checkMeta->setCartItemEntity($cartItemEntity);
        $checkMeta->setProductEntity($productEntity);
        $checkMeta->setProductSkuEntity($productSkuEntity);
        $checkMeta->setAreaEntity($areaEntity);

        $pipelineConfig->setClosure(function () use ($checkMeta) {
            $wrapper = new CheckResultWrapper($checkMeta->getCouponEntity());
            $wrapper->setPass(true);
            return $wrapper;
        });

        return [$pipelineConfig, $checkMeta];
    }

    /**
     * @param CartItemEntity $cartItemEntity
     * @param CouponCodeEntity[] $coupons
     * @return  CouponCodeEntity[]
     * @throws \Exception
     */
    public static function filterByCartItemEntity(CartItemEntity $cartItemEntity, array $coupons)
    {
        if (empty($coupons)) {
            return [];
        }

        list($pipelineConfig, $checkMeta) = self::getConfigAndCheckMeta($cartItemEntity);
        // 优惠券过滤条件
        foreach ($coupons as $key => $coupon) {
            $checkMeta->setCouponEntity($coupon);
            /** * @var CheckResultWrapper $wrapper */
            $wrapper = PipelineProxy::execute($checkMeta, $pipelineConfig);
            if (!$wrapper->isPass()) {
                unset($coupons[$key]);
                continue;
            }
        }

        return $coupons;
    }

    /**
     * 根据是否能使用分组
     * @param CartItemEntity $cartItemEntity
     * @param array $coupons
     * @return array
     * @throws \Exception
     */
    public static function groupByUseAble(CartItemEntity $cartItemEntity, array $coupons)
    {
        $useAble = [];
        $unUseAble = [];

        if (empty($coupons)) {
            return [$useAble, $unUseAble];
        }

        list($pipelineConfig, $checkMeta) = self::getConfigAndCheckMeta($cartItemEntity);
        foreach ($coupons as $key => $coupon) {
            $checkMeta->setCouponEntity($coupon);
            /** * @var CheckResultWrapper $wrapper */
            $wrapper = PipelineProxy::execute($checkMeta, $pipelineConfig);
            if ($wrapper->isPass()) {
                $useAble[] = $wrapper;
            } else {
                $unUseAble[] = $wrapper;
            }
        }

        return [$useAble, $unUseAble];
    }
}
